package systems.dla 
{
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.DisplayObject;
	import flash.display.Shape;
	import flash.display.Sprite;
	import flash.events.TimerEvent;
	import flash.geom.ColorTransform;
	import flash.geom.Matrix;
	import flash.geom.Point;
	import flash.utils.Dictionary;
	import flash.utils.Timer;
	import graphics.raster.Bresenham;
	
	/**
	 * @author Nicolas Barradeau
	 * http://en.nicoptere.net
	 */
	public class DLA extends Sprite
	{
		
		private var _bitmap:Bitmap;
		private var _bitmapData:BitmapData;
		
		private var _tmpBmp:Bitmap;
		private var _tmpBd:BitmapData;
		
		private var _buffer:BitmapData;
		
		
		static private var emitters:Dictionary = new Dictionary( true );
		private var particles:Vector.<DLAParticle> = new Vector.<DLAParticle>();
		private var _particleSize:Number = 1;
		private var _ipf:int = 1;
		private var _color:uint = 0xFFFFFF;
		
		private var timer:Timer;
		
		public function DLA( width:int = 800, height:int = 600 ) 
		{ 
			this._particleSize = particleSize;
			
			_bitmapData = new BitmapData( width, height, true, 0 );
			_bitmap = new Bitmap( _bitmapData, 'auto', false );
			
			_tmpBmp = new Bitmap( new BitmapData( width, height, true, 0 ), 'auto', false );
			
			addChild( bitmap );
			addChild( _tmpBmp );
			
			this.particleSize = 1;
			
			timer = new Timer(0);
			timer.addEventListener( TimerEvent.TIMER, onTick );
			
		}
		
		public function start():void
		{
			timer.start();
		}
		
		public function stop():void
		{
			timer.stop();
		}
		
		private function onTick(e:TimerEvent):void 
		{
			update();
		}
		
		public function update():void
		{
			for each( var e:DLAEmitter in emitters )
			{
				for ( var i:int = 0; i < ipf; i++ )
				{
					particles.push( e.emit() );
				}
			}
			
			var p:DLAParticle;
			var tl:Point = new Point();
			var matrix:Matrix = new Matrix();
			var tmp:Vector.<DLAParticle> = new Vector.<DLAParticle>();
			
			Bresenham.bitmapData = bitmapData;
			
			_tmpBmp.bitmapData.colorTransform( _tmpBmp.bitmapData.rect, new ColorTransform( 1,1,1,.9 ) );
			//_tmpBmp.bitmapData.fillRect( _tmpBmp.bitmapData.rect, 0 );
			
			_tmpBmp.bitmapData.lock();
			
			for each( p in particles )
			{
				
				p.update();
				
				if( bitmapData.hitTest( tl, 0xFF, _buffer, p, 0 ) )
				{
					
					matrix.identity();
					matrix.translate( p.x, p.y );
					bitmapData.draw( _buffer, matrix ); 
					
					//Bresenham.drawLine( p.x - p.velocity.x * particleSize * 2, p.y - p.velocity.y * particleSize * 2, p.x, p.y, 0xFF << 24 | color );
					
				}
				else
				{
					
					if ( bitmapData.rect.containsPoint( p ) )
					{
						_tmpBmp.bitmapData.setPixel32( p.x, p.y, 0xFF<<24 | color ); 
						tmp.push( p );
					}
					
				}
				
			}
			_tmpBmp.bitmapData.unlock();
			particles = tmp.concat();
		}
		
		static public function register( emitter:DLAEmitter ) :void
		{	
			emitters[ emitter ] = emitter;
		}
		
		static public function unregister( emitter:DLAEmitter ) :void
		{	
			delete emitters[ emitter ];
		}
		
		public function get bitmap():Bitmap { return _bitmap; }
		public function get bitmapData():BitmapData { return _bitmapData; }
		
		public function get particleSize():Number { return _particleSize; }
		
		public function set particleSize(value:Number):void 
		{
			
			_particleSize = value;
			
			if ( value < 2 )
			{
				_buffer = new BitmapData( 2, 2, true, 0xFF<<24 | color );
				return;
			}
			
			var canvas:Shape = new Shape();
			canvas.graphics.beginFill( color );
			canvas.graphics.drawCircle( value * .5, value * .5, value * .5 );
			
			_buffer = new BitmapData( value, value, true, 0 );
			_buffer.draw( canvas );
			
			canvas.graphics.clear();
			canvas = null;
			
		}
		
		public function get ipf():int { return _ipf; }
		
		public function set ipf(value:int):void 
		{
			_ipf = value;
		}
		
		public function get color():uint { return _color; }
		
		public function set color(value:uint):void 
		{
			_color = value;
			particleSize = _particleSize;
		}
		
		
		
	}

}